package com.spring.arch.uaa.config;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.spring.arch.common.security.SecurityProperties;
import com.spring.arch.common.security.SecurityProperties;
import com.spring.arch.common.security.UserPrincipal;
import com.spring.arch.uaa.oauth2.dynamic.DynamicallyUrlProcessor;
import com.spring.arch.uaa.oauth2.dynamic.DynamicallyUrlSecurityMetadataSource;
import com.spring.arch.uaa.oauth2.dynamic.UrlPattern;
import com.spring.arch.uaa.oauth2.encoder.MD5PasswordEncoder;
import com.spring.arch.uaa.oauth2.handler.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Web应用安全配置
 *
 * @author Frank
 */
@EnableConfigurationProperties(SecurityProperties.class)
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Qualifier("urlRoleCache")
    @Autowired
    private Map<UrlPattern, Collection<ConfigAttribute>> requestMap;
    @Autowired
    private SecurityProperties securityProperties;
    @Autowired
    private PasswordSaltSource passwordSaltSource;
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 初始化密码加密器
     */
    @Bean
    @Primary
    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();
        return new MD5PasswordEncoder();
    }

    /**
     * 初始化认证管理器
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 初始化动态资源元数据
     */
    @Bean
    public DynamicallyUrlSecurityMetadataSource securityMetadataSource() {
        return new DynamicallyUrlSecurityMetadataSource(requestMap, securityProperties.getExcludeAuthUrl());
    }

    /**
     * 初始化对象后置处理器
     * - 访问决策管理器
     * - 动态资源元数据
     */
    @Bean
    public DynamicallyUrlProcessor dynamicallyUrlProcessor() {
        return new DynamicallyUrlProcessor(securityMetadataSource());
    }

    /**
     * 初始化未认证处理器
     */
    @Bean
    public SecurityAuthenticationEntryPoint unauthenticatedHandler() {
        return new SecurityAuthenticationEntryPoint();
    }

    /**
     * 初始化URL未授权处理器
     */
    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return new SecurityAccessDeniedHandler();
    }

    /**
     * 初始化用户名密码认证过滤器
     */
    @Bean
    public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception {
        UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(passwordSaltSource);
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }

    /**
     * 初始化登陆认证器
     */
    @Bean
    public LoginAuthenticationProvider loginAuthenticationProvider() {
        return new LoginAuthenticationProvider(userDetailsService, passwordEncoder());
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(loginAuthenticationProvider())
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        // 密码加盐设计
//        http.addFilterAfter(usernamePasswordAuthenticationFilter(), org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.class);
//    }

//    @Bean("tokenLocalCache")
//    public Cache<String, UserPrincipal> buildTokenCache() {
//        Integer timeout = securityProperties.getAuth().getDefaultAccessTokenTimeout();
//        // 通过CacheBuilder构建一个缓存实例
//        return CacheBuilder.newBuilder()
//                // 设置缓存的最大容量
//                .maximumSize(1000)
//                // 设置失效时间为JWT的失效时间
//                .expireAfterWrite(timeout, TimeUnit.MILLISECONDS)
//                // 并发数为cpu核心进程数
//                .concurrencyLevel(Runtime.getRuntime().availableProcessors())
//                // 开启缓存统计
//                .recordStats()
//                .build();
//    }
}